package jp.tonosama.komoki.SimpleGolfScorer2.viewer;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnClickListener;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.Images;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import jp.tonosama.komoki.SimpleGolfScorer2.R;
import jp.tonosama.komoki.SimpleGolfScorer2.Util;
import jp.tonosama.komoki.SimpleGolfScorer2.data.GolfScoreData;
import jp.tonosama.komoki.achartengine.AxesMetaData;
import jp.tonosama.komoki.achartengine.SeriesMetaData;
import jp.tonosama.komoki.achartengine.XYChart;
import jp.tonosama.komoki.achartengine.activity.ChartConfig;
import jp.tonosama.komoki.achartengine.activity.DataSeriesAttributes;
import jp.tonosama.komoki.achartengine.activity.LineChartActivity;
import jp.tonosama.komoki.achartengine.activity.RenderingAxesContainer;
import jp.tonosama.komoki.achartengine.renderer.XYMultipleSeriesRenderer;
import jp.tonosama.komoki.achartengine.view.FlowLayout;
import jp.tonosama.komoki.achartengine.view.PlotView;
import jp.tonosama.komoki.achartengine.view.VerticalLabelView;
import jp.tonosama.komoki.core.IntentConstants;

/**
 * @author Komoki
 */
public class GraphActivity extends LineChartActivity {

    /** */
    private int mBaseLineType = ChartConfig.DEFAULT_BASELINE_TYPE;
    /** */
    private Uri mImgUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
    /**  */
    private GolfScoreData mScoreData;
    /**  */
    private Button mOutputBtn;
    /**  */
    private Button mSettingBtn;

    @Override
    protected int getLayoutResourceId() {
        return R.layout.xy_chart_activity;
    }

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getScoreData() == null) {
            return;
        }
    }

    /**
     * startOutputProgressIfNeed
     */
    private void startOutputProgressIfNeed() {

        if (getScoreData().isOutputImageFlg()) {
            getScoreData().setOutputImageFlg(false);
            final ProgressDialog progressDialog = new ProgressDialog(this);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            progressDialog
                    .setMessage(getResources().getString(R.string.send_by_email_output_graph));
            progressDialog.setCancelable(false);
            progressDialog.show();
            Runnable runnable = new Runnable() {

                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        Log.e("Runnable", "InterruptedException");
                    }
                    GraphActivity.this.runOnUiThread(new Runnable() {

                        public void run() {
                            Uri imageUri = getOutputImageUri();
                            finish();
                            progressDialog.dismiss();
                            Intent intent = new Intent(getApplicationContext(), ScoreViewer.class);
                            String subject = getIntent().getStringExtra(Intent.EXTRA_SUBJECT);
                            String text = getIntent().getStringExtra(Intent.EXTRA_TEXT);
                            intent.putExtra(Intent.EXTRA_SUBJECT, subject);
                            intent.putExtra(Intent.EXTRA_TEXT, text);
                            intent.putExtra(Util.EXTRAS_IMAGE_URI_GRAPH, imageUri);
                            getScoreData().setOutputImageFlg(true);
                            intent.putExtra(GolfScoreData.EXTRAS_SEND_SCORE_DATA, getScoreData());
                            startActivity(intent);
                        }
                    });
                }
            };
            (new Thread(runnable)).start();
        }
    }

    /**
     * @return Uri
     */
    private Uri getOutputImageUri() {

        mOutputBtn.setVisibility(View.GONE);
        mSettingBtn.setVisibility(View.GONE);

        long dateTaken = System.currentTimeMillis();
        String name = createName(dateTaken) + ".png";
        String filename = name;
        String directory = Environment.getExternalStorageDirectory().toString() + "/"
                + ScoreViewer.CAPTURE_IMAGE_DIR;
        String filePath = directory + "/" + filename;
        if (!saveOutputImageFile(directory, filename)) {
            return null;
        }
        ContentValues values = new ContentValues(7);
        values.put(Images.Media.TITLE, name);
        values.put(Images.Media.DISPLAY_NAME, filename);
        values.put(Images.Media.DATE_TAKEN, dateTaken);
        values.put(Images.Media.MIME_TYPE, "image/png");
        values.put(Images.Media.DATA, filePath);
        ContentResolver cr = getContentResolver();
        mImgUri = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

        mOutputBtn.setVisibility(View.VISIBLE);
        mSettingBtn.setVisibility(View.VISIBLE);

        return mImgUri;
    }

    /**
     * @param directory ディレクトリ名
     * @param filename ファイル名
     * @return true:保存成功 false:保存失敗
     */
    private boolean saveOutputImageFile(final String directory, final String filename) {

        View disp = findViewById(R.id.graph_view_captured_area);
        disp.setDrawingCacheEnabled(true);
        Bitmap source = disp.getDrawingCache();
        if (source == null) {
            return false;
        }
        OutputStream outputStream = null;
        try {
            File dir = new File(directory);
            if (!dir.exists()) {
                if (!dir.mkdirs()) {
                    throw new IOException();
                }
            }
            File file = new File(directory, filename);
            if (file.createNewFile()) {
                outputStream = new FileOutputStream(file);
                source.compress(CompressFormat.PNG, 100, outputStream);
            }
        } catch (FileNotFoundException ex) {
            Toast.makeText(this, "FileNotFoundException", Toast.LENGTH_SHORT).show();
            return false;
        } catch (IOException ex) {
            Toast.makeText(this, "Please insert SD card.", Toast.LENGTH_SHORT).show();
            return false;
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

    /**
     * @return GolfScoreData
     */
    private GolfScoreData getScoreData() {
        return mScoreData;
    }

    /**
     * @param scoreData GolfScoreData
     */
    private void setScoreData(final GolfScoreData scoreData) {
        mScoreData = scoreData;
    }

    /**
     * @param button button
     */
    private void setupOutputButtonAction(final Button button) {

        button.setOnClickListener(new View.OnClickListener() {

            public void onClick(final View v) {
                final Uri imgUri = getOutputImageUri();
                if (imgUri == null) {
                    return;
                }
                AlertDialog.Builder dialog = new AlertDialog.Builder(GraphActivity.this);
                dialog.setIcon(R.drawable.ic_menu_question);
                dialog.setTitle(getResources().getString(R.string.menu_output_graph));
                dialog.setMessage(getResources().getString(R.string.dlg_output_image_msg_graph));
                dialog.setPositiveButton(
                        getResources().getString(R.string.dlg_output_image_by_email),
                        new DialogInterface.OnClickListener() {

                            public void onClick(final DialogInterface dialog, final int which) {
                                // Output to E-Mail
                                Intent mIntent = new Intent();
                                mIntent.setAction(Intent.ACTION_SEND);
                                mIntent.setType("message/rfc822");
                                mIntent.putExtra(Intent.EXTRA_STREAM, imgUri);
                                startActivity(mIntent);
                            }
                        });
                dialog.setNegativeButton(
                        getResources().getString(R.string.dlg_output_image_by_viewer), null);
                dialog.show();
            }
        });
    }

    /**
     * @param button button
     */
    private void setupSettingButtonAction(final Button button) {

        button.setOnClickListener(new View.OnClickListener() {

            public void onClick(final View v) {

                AlertDialog.Builder dialog = new AlertDialog.Builder(GraphActivity.this);
                dialog.setTitle(getResources().getString(R.string.dlg_chgb_title));
                dialog.setSingleChoiceItems(ChartConfig.BASE_LINE_TYPE_TITLE, mBaseLineType,
                        new OnClickListener() {

                            public void onClick(final DialogInterface dialog, final int item) {
                                mBaseLineType = item;
                                dialog.dismiss();
                                redrawGraph();
                                restartGraphActivity();
                                // put shared preferrence
                                SharedPreferences pref = getSharedPreferences(
                                        ChartConfig.PREF_GRAPH_SETTING, MODE_PRIVATE);
                                Editor edit = pref.edit();
                                edit.putInt(ChartConfig.PREF_GRAPH_BASIS_TYPE_KEY, mBaseLineType);
                                edit.commit();
                            }
                        });
                dialog.create().show();
                /**/
            }
        });
    }

    public void redrawGraph() {

        int mBestPlayer = checkBestPlayer(getScoreData());
        int mBaseNum = getScoreData().getEachHolePar()[0];
        if (mBaseLineType != ChartConfig.BASE_LINE_TYPE_INT.length - 1) {
            mBaseNum = ChartConfig.BASE_LINE_TYPE_INT[mBaseLineType];
        }
        // for FailSafe s
        int mNullCheck = 0;
        for (int i = 0; i < Util.TOTAL_HOLE_COUNT; i++) {
            mNullCheck += getScoreData().getAbsoluteScore(0)[i];
        }
        if (mNullCheck == 0) {
            finish();
            return;
        }
        // for FailSafe e
        updateGolfScoreData(getScoreData(), mBaseNum, mBestPlayer);
    }

    /**
     * @param golfScoreData golfScoreData
     * @param currBaseNum currBaseNum
     * @param bestPlayer bestPlayer
     */
    private void updateGolfScoreData(final GolfScoreData golfScoreData, final int currBaseNum,
            final int bestPlayer) {
        int baseNum = currBaseNum;
        if (mBaseLineType == 0) {
            for (int i = 0; i < golfScoreData.getNames().length; i++) {
                golfScoreData.getDemoSeries(i)[0] = 0 + golfScoreData.getPlayersHandi()[i]
                        - golfScoreData.getPlayersHandi()[bestPlayer];
            }
        } else {
            for (int i = 0; i < golfScoreData.getNames().length; i++) {
                golfScoreData.getDemoSeries(i)[0] = 0 - golfScoreData.getPlayersHandi()[i];
            }
        }
        for (int i = 1; i < Util.TOTAL_HOLE_COUNT + 1; i++) {
            baseNum = golfScoreData.getEachHolePar()[i - 1];
            if (mBaseLineType != ChartConfig.BASE_LINE_TYPE_INT.length - 1) {
                baseNum = ChartConfig.BASE_LINE_TYPE_INT[mBaseLineType];
            }
            for (int j = 0; j < golfScoreData.getNames().length; j++) {
                if (golfScoreData.getAbsoluteScore(j)[i - 1] != 0) {
                    golfScoreData.getDemoSeries(j)[i] = golfScoreData.getDemoSeries(j)[i - 1]
                            + (golfScoreData.getAbsoluteScore(j)[i - 1]
                                    - golfScoreData.getEachHolePar()[i - 1] - baseNum);
                }
            }
            if (mBaseLineType == 0) {
                for (int j = 0; j < golfScoreData.getNames().length; j++) {
                    int score = golfScoreData.getAbsoluteScore(bestPlayer)[i - 1];
                    golfScoreData.getDemoSeries(j)[i] = golfScoreData.getDemoSeries(j)[i - 1]
                            + (score - golfScoreData.getAbsoluteScore(j)[i - 1]);
                }
            }
        }
        for (int i = 0; i < golfScoreData.getNames().length; i++) {
            if (golfScoreData.getPlayersAlpha()[i] == 0) {
                for (int j = 0; j < golfScoreData.getDemoSeries(0).length; j++) {
                    golfScoreData.getDemoSeries(i)[j] = 0;
                }
            }
        }
    }

    /**
     * @param dateTaken dateTaken
     * @return date String
     */
    private static String createName(final long dateTaken) {
        return DateFormat.format("yyyy-MM-dd_kk.mm.ss", dateTaken).toString();
    }

    /**
     * restartGraphActivity
     */
    public void restartGraphActivity() {
        Intent i = new Intent(getApplicationContext(), GraphActivity.class);
        i.putExtra(Intent.EXTRA_TITLE, getScoreData().getHoleTitle());
        i.putExtra(IntentConstants.Meta.Axes.EXTRA_FORMAT_STRING_Y, "%.0f");
        i.putExtra(
                IntentConstants.Meta.Series.EXTRA_SERIES_COLORS,
                new int[] { Color.argb(getScoreData().getPlayersAlpha()[0], 255, 0, 0),
                        Color.argb(getScoreData().getPlayersAlpha()[1], 0, 0, 255),
                        Color.argb(getScoreData().getPlayersAlpha()[2], 255, 0, 128),
                        Color.argb(getScoreData().getPlayersAlpha()[3], 0, 128, 0) });
        i.putExtra(Intent.EXTRA_UID, mBaseLineType);
        i.putExtra(GolfScoreData.EXTRAS_SEND_SCORE_DATA, getScoreData());
        startActivity(i);
        finish();
    }

    /**
     * @return seriesLabelList
     */
    public ArrayList<AxesMetaData> createSeriesLabelList() {
        ArrayList<AxesMetaData> seriesLabelList = new ArrayList<AxesMetaData>();
        for (int i = 0; i < getScoreData().getDemoAxesLabels().length; i++) {
            AxesMetaData metaData = new AxesMetaData();
            metaData.setTitle(getScoreData().getDemoAxesLabels()[i]);
            seriesLabelList.add(metaData);
        }
        return seriesLabelList;
    }

    /**
     * @return SortedSeriesList
     */
    public List<List<List<Number>>> createSortedSeriesList() {

        List<List<List<Number>>> sortedSeriesList = new ArrayList<List<List<Number>>>();
        List<List<Number>> xDatas = new ArrayList<List<Number>>();
        xDatas.add(new ArrayList<Number>());
        for (int i = 0; i < getScoreData().getDemoXaxisData().length; i++) {
            xDatas.get(0).add((float) getScoreData().getDemoXaxisData()[i]);
        }
        ArrayList<List<Number>> yDatas = new ArrayList<List<Number>>();
        for (int i = 0; i < getScoreData().getNames().length; i++) {
            ArrayList<Number> yData = new ArrayList<Number>();
            for (int j = 0; j < getScoreData().getDemoSeriesList()[i].length; j++) {
                yData.add((float) getScoreData().getDemoSeriesList()[i][j]);
            }
            yDatas.add(yData);
        }
        sortedSeriesList.add(xDatas);
        sortedSeriesList.add(yDatas);

        return sortedSeriesList;
    }

    /**
     * @param axesContainer axesContainer
     * @return SeriesMetadataList
     */
    public ArrayList<SeriesMetaData> createSeriesMetadataList(
            final RenderingAxesContainer axesContainer) {

        ArrayList<SeriesMetaData> seriesMetaDataList = new ArrayList<SeriesMetaData>();
        int[] extraSeriesColors = getIntent().getIntArrayExtra(
                IntentConstants.Meta.Series.EXTRA_SERIES_COLORS);
        for (int i = 0; i < getScoreData().getNames().length; i++) {
            SeriesMetaData seriesMetaData = new SeriesMetaData();
            seriesMetaData.setTitle(getScoreData().getNames()[i]);
            seriesMetaData.setColor(extraSeriesColors[i]);
            seriesMetaDataList.add(seriesMetaData);
        }
        axesContainer.setTitles(new String[seriesMetaDataList.size()]);
        for (int i = 0; i < seriesMetaDataList.size(); i++) {
            axesContainer.getTitles()[i] = seriesMetaDataList.get(i).getTitle();
        }
        return seriesMetaDataList;
    }

    /**
     * @param golfScoreData GolfScoreData
     * @return BestPlayer
     */
    public int checkBestPlayer(final GolfScoreData golfScoreData) {
        int bestPlayer = 0;
        int[] score = { -golfScoreData.getPlayersHandi()[0], -golfScoreData.getPlayersHandi()[1],
                -golfScoreData.getPlayersHandi()[2], -golfScoreData.getPlayersHandi()[3] };
        for (int i = 0; i < golfScoreData.getEachHolePar().length; i++) {
            score[0] += golfScoreData.getAbsoluteScore(0)[i];
            score[1] += golfScoreData.getAbsoluteScore(1)[i];
            score[2] += golfScoreData.getAbsoluteScore(2)[i];
            score[3] += golfScoreData.getAbsoluteScore(3)[i];
        }
        int playerNum = 0;
        for (int i = 0; i < golfScoreData.getPlayersHandi().length; i++) {
            if (golfScoreData.getNames()[i].trim().length() != 0) {
                playerNum++;
            }
        }
        int bestScore = score[0];
        for (int i = 1; i < playerNum; i++) {
            if (score[i] < bestScore) {
                bestPlayer = i;
            }
            bestScore = score[bestPlayer];
        }
        return bestPlayer;
    }

    @Override
    protected void initLayout() {
        //
    }

    @Override
    protected void initData() {
        Serializable data = getIntent().getSerializableExtra(GolfScoreData.EXTRAS_SEND_SCORE_DATA);
        if (data == null || !(data instanceof GolfScoreData)) {
            return;
        }
        setScoreData((GolfScoreData) data);
        // get shared preferrence
        SharedPreferences mGraphPref = getSharedPreferences(ChartConfig.PREF_GRAPH_SETTING,
                MODE_PRIVATE);
        mBaseLineType = mGraphPref.getInt(ChartConfig.PREF_GRAPH_BASIS_TYPE_KEY,
                ChartConfig.DEFAULT_BASELINE_TYPE);
        Log.v(TAG, "graph basis type : " + String.valueOf(mBaseLineType));
        redrawGraph();
        mOutputBtn = (Button) findViewById(R.id.graph_output_button);
        mSettingBtn = (Button) findViewById(R.id.graph_setting_button);
        mSettingBtn.setText(String.format(
                getResources().getString(R.string.btn_change_graph_basis),
                ChartConfig.BASE_LINE_TYPE_STR[mBaseLineType]));

        setupOutputButtonAction(mOutputBtn);
        setupSettingButtonAction(mSettingBtn);
        this.setView((PlotView) findViewById(R.id.chart_view));
        String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
        ((TextView) findViewById(R.id.chart_title_placeholder)).setText(title);
        startOutputProgressIfNeed();
    }

    @Override
    protected void postChartPopulationCallback() {

        XYChart xyChart = (XYChart) getChart();

        if (xyChart == null) {
            Log.e(TAG, "Chart is null; finishing activity.");
            finish();
            return;
        }
        XYMultipleSeriesRenderer renderer = xyChart.getRenderer();
        renderer.setShowXAxis(getIntent().getBooleanExtra(
                IntentConstants.Meta.Axes.EXTRA_AXIS_VISIBLE_X, true));
        renderer.setShowYAxis(getIntent().getBooleanExtra(
                IntentConstants.Meta.Axes.EXTRA_AXIS_VISIBLE_Y, true));

        ((TextView) findViewById(R.id.chart_x_axis_title)).setText(xyChart.getRenderer()
                .getXTitle());
        ((VerticalLabelView) findViewById(R.id.chart_y_axis_title)).setText(xyChart.getRenderer()
                .getYTitle());

        if (renderer.hasSecondaryYAxis()) {

            VerticalLabelView verticalLabel = //
            (VerticalLabelView) findViewById(R.id.chart_y_secondary_axis_title);

            verticalLabel.setText(xyChart.getRenderer().getYSecondaryTitle());
            verticalLabel.setVisibility(View.VISIBLE);

            findViewById(R.id.chart_y_secondary_axis_spacer).setVisibility(View.INVISIBLE);
        }
        FlowLayout predicateLayout = (FlowLayout) findViewById(R.id.predicate_layout);
        List<DataSeriesAttributes> seriesAttributesList = getSeriesAttributesList(getChart());
        populateLegend(predicateLayout, seriesAttributesList);
    }
}
